#include "parameters.h"
#include "globals.h"
#include "main.h"

void ParamInit(void)
{
	uint8_t i;
	sParamGeneral paramGeneral;
	Flash_M25P64_Read_Buffer((uint8_t*)&paramGeneral, ADDRESS_PARAM_GENERAL, sizeof(paramGeneral));

	if(paramGeneral.final != FINAL_OK)	{	/* if settings are empty, usb mode */
		HAL_PWR_EnableBkUpAccess();
		BACUP_STATUS->BACUP_STATUS_REG = USB_ENABLED;
		HAL_PWR_DisableBkUpAccess();
		NVIC_SystemReset();
	}
	else
	{
		bootMode = BOOT_MODE_NORMAL;
		for(i=0;i<6;i++)
		{
			if(i<4)
			{
				startParam.net.ip_addr[i] = paramGeneral.ip_addr_default[i];
				startParam.net.gw_addr[i] = paramGeneral.gateway_default[i];
				startParam.net.sub[i] = paramGeneral.netmask_default[i];
				startParam.net.ip_dest[i] = paramGeneral.dest_ip[i];
			}
			startParam.net.mac[i] = paramGeneral.mac[i];
		}
		startParam.id = paramGeneral.id_plk;
		startParam.net.net_use = paramGeneral.network_enabled;

		startParam.poll_interval[0] = paramGeneral.poll_interval[0];
		startParam.poll_interval[1] = paramGeneral.poll_interval[1];
		startParam.poll_interval[2] = paramGeneral.poll_interval[2];

		startParam.modbus_id_lines[0] = paramGeneral.modbus_id_line[0];
		startParam.modbus_id_lines[1] = paramGeneral.modbus_id_line[1];
		startParam.modbus_id_lines[2] = paramGeneral.modbus_id_line[2];
		startParam.modbus_id_lines[3] = paramGeneral.modbus_id_line[3];

		startParam.net.destPort = paramGeneral.dest_port;
	}
}

void Flash_Mem_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC->FLASH_M25P64_RCC_AHB |= FLASH_M25P64_RCC_AHB1_EN;
	GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
	/* MISO SPI */
	GPIO_InitStruct.Pin = FLASH_MISO_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(FLASH_MISO_PORT, &GPIO_InitStruct);
	/* MOSI SPI */
	GPIO_InitStruct.Pin = FLASH_MOSI_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(FLASH_MOSI_PORT, &GPIO_InitStruct);
	/* SCLK SPI */
	GPIO_InitStruct.Pin = FLASH_SCLK_PIN;
	HAL_GPIO_Init(FLASH_SCLK_PORT, &GPIO_InitStruct);
	/* CS M25P64 */
	GPIO_InitStruct.Pin = FLASH_M25P64_CS_PIN;
	HAL_GPIO_Init(FLASH_M25P64_CS_PORT, &GPIO_InitStruct);
	/* Write-Protecion M25P64 */
	GPIO_InitStruct.Pin = FLASH_M25P64_WP_PIN;
	HAL_GPIO_Init(FLASH_M25P64_WP_PORT, &GPIO_InitStruct);
	FLASH_M25P64_CS_1;
	FLASH_MOSI_1;
	FLASH_M25P64_WP_1;
}

uint8_t Flash_Read_Byte(void)
{
	uint8_t i;
	uint8_t data = 0;
	_delay(100);
	FLASH_MOSI_0;
	FLASH_SCLK_0;
	for(i=0;i<8;i=i+1)
	{
		data = data << 1;
		if(FLASH_MISO_STATE)
			data |= 0x01;
		else
			data &= 0xFE;
		_delay(100);
		FLASH_SCLK_1;
		_delay(100);
		FLASH_SCLK_0;
	}
	FLASH_MOSI_1;
	return(data);
}

void Flash_Send_Byte(uint8_t data)
{
	uint8_t i;
	_delay(100);
	FLASH_MOSI_0;
	FLASH_SCLK_0;
	for (i=0;i<8;i++)
	{
		if(data & 0x80)
			FLASH_MOSI_1;
		else
			FLASH_MOSI_0;
		_delay(100);
		FLASH_SCLK_1;
		_delay(100);
		FLASH_SCLK_0;
		data = data <<1;
	}
	FLASH_MOSI_1;
}

void Flash_M25P64_Set_Write(uint8_t state)
{
	FLASH_M25P64_CS_0;
	_delay(10);
	if(state ==FLASH_M25P64_WRITE_EN)
		Flash_Send_Byte(_FLASH_CMD_WREN);
	else
		Flash_Send_Byte(_FLASH_CMD_WRDIS);
	FLASH_M25P64_CS_1;
}

void Flash_M25p64_Wait_For_Write_End(void)
{
	uint8_t status = 0;
	FLASH_M25P64_CS_0;
	_delay(10);
	/*!< Send "Read Status Register" instruction */
	Flash_Send_Byte(_FLASH_CMD_RDSR);
	/*!< Loop as long as the memory is busy with a write cycle */
	do
	{
		/*!< Send a dummy byte to generate the clock needed by the FLASH
    and put the value of the status register in FLASH_Status variable */
		status = Flash_Read_Byte();
	}
	while ((status & _FLASH_WIP_FLAG) == SET); /* Write in progress */
	/*!< Deselect the FLASH: Chip Select high */
	FLASH_M25P64_CS_1;
}

void Flash_M25P64_EraseSector(uint8_t addrSector)
{
	Flash_M25P64_Set_Write(FLASH_M25P64_WRITE_EN);
	_delay(10);
	/*!< Sector Erase */
	/*!< Select the FLASH: Chip Select low */
	FLASH_M25P64_CS_0;
	_delay(10);
	/*!< Send Sector Erase instruction */
	Flash_Send_Byte(_FLASH_CMD_SE);
	/*!< Send SectorAddr high nibble address byte */
	Flash_Send_Byte((addrSector & 0xFF0000) >> 16);
	/*!< Send SectorAddr medium nibble address byte */
	Flash_Send_Byte((addrSector & 0xFF00) >> 8);
	/*!< Send SectorAddr low nibble address byte */
	Flash_Send_Byte(addrSector & 0xFF);
	/*!< Deselect the FLASH: Chip Select high */
	FLASH_M25P64_CS_1;
	_delay(10);
	Flash_M25p64_Wait_For_Write_End();
	Flash_M25P64_Set_Write(FLASH_M25P64_WRITE_DIS);
}

void FLASH_M25P64_Write_Page(uint8_t* pBuffer, uint32_t writeAddr, uint16_t numByteToWrite)
{
	/*!< Enable the write access to the FLASH */
	Flash_M25P64_Set_Write(FLASH_M25P64_WRITE_EN);
	_delay(10);
	/*!< Select the FLASH: Chip Select low */
	FLASH_M25P64_CS_0;
	_delay(10);
	/*!< Send "Write to Memory " instruction */
	Flash_Send_Byte(_FLASH_CMD_WRITE);
	/*!< Send WriteAddr high nibble address byte to write to */
	Flash_Send_Byte((writeAddr & 0xFF0000) >> 16);
	/*!< Send WriteAddr medium nibble address byte to write to */
	Flash_Send_Byte((writeAddr & 0xFF00) >> 8);
	/*!< Send WriteAddr low nibble address byte to write to */
	Flash_Send_Byte(writeAddr & 0xFF);
	/*!< while there is data to be written on the FLASH */
	while (numByteToWrite--)
	{
		/*!< Send the current byte */
		Flash_Send_Byte(*pBuffer);
		/*!< Point on the next byte to be written */
		pBuffer++;
	}
	/*!< Deselect the FLASH: Chip Select high */
	FLASH_M25P64_CS_1;
	/*!< Wait the end of Flash writing */
	Flash_M25p64_Wait_For_Write_End();
	Flash_M25P64_Set_Write(FLASH_M25P64_WRITE_DIS);
}

void FLASH_M25P64_Write_Buffer(uint8_t* pBuffer, uint32_t writeAddr, uint16_t len)
{
	uint8_t numOfPage = 0;
	uint8_t numOfSingle = 0;
	uint16_t addr = 0;

	addr = writeAddr % _FLASH_SPI_PAGESIZE;
	numOfPage =  len / _FLASH_SPI_PAGESIZE;
	numOfSingle = len % _FLASH_SPI_PAGESIZE;

	if (addr == 0) /*!< WriteAddr is sFLASH_PAGESIZE aligned  */
	{
		if (numOfPage == 0) /*!< NumByteToWrite < sFLASH_PAGESIZE */
		{
			FLASH_M25P64_Write_Page(pBuffer, writeAddr, len);
		}
		else /*!< NumByteToWrite > sFLASH_PAGESIZE */
		{
			while (numOfPage--)
			{
				FLASH_M25P64_Write_Page(pBuffer, writeAddr, _FLASH_SPI_PAGESIZE);
				writeAddr +=  _FLASH_SPI_PAGESIZE;
				pBuffer += _FLASH_SPI_PAGESIZE;
			}

			FLASH_M25P64_Write_Page(pBuffer, writeAddr, numOfSingle);
		}
	}
}

void Flash_M25P64_Read_Buffer(uint8_t* pBuffer, uint32_t addr, uint16_t numByteToRead)
{
	/*!< Select the FLASH: Chip Select low */
	FLASH_M25P64_CS_0;
	/*!< Send "Read from Memory " instruction */
	Flash_Send_Byte(_FLASH_CMD_READ);
	/*!< Send ReadAddr high nibble address byte to read from */
	Flash_Send_Byte((addr & 0xFF0000) >> 16);
	/*!< Send ReadAddr medium nibble address byte to read from */
	Flash_Send_Byte((addr & 0xFF00) >> 8);
	/*!< Send ReadAddr low nibble address byte to read from */
	Flash_Send_Byte(addr & 0xFF);
	while (numByteToRead--) /*!< while there is data to be read */
	{
		/*!< Read a byte from the FLASH */
		*pBuffer = Flash_Read_Byte();
		/*!< Point to the next location where the byte read will be saved */
		pBuffer++;
	}
	/*!< Deselect the FLASH: Chip Select high */
	FLASH_M25P64_CS_1;
}

uint32_t Flash_M25P64_Read_ID(void)
{
	uint32_t id;
	/*!< Select the FLASH: Chip Select low */
	FLASH_M25P64_CS_0;
	_delay(10);
	/*!< Send "RDID " instruction */
	Flash_Send_Byte(_FLASH_CMD_RDID);
	/*!< Read a byte from the FLASH */
	id = Flash_Read_Byte();
	id = id <<8;
	/*!< Read a byte from the FLASH */
	id |= Flash_Read_Byte();
	id = id <<8;
	/*!< Read a byte from the FLASH */
	id |= Flash_Read_Byte();
	/*!< Deselect the FLASH: Chip Select high */
	FLASH_M25P64_CS_1;
	FLASH_MOSI_1;
	_delay(10);
	return id;
}

void Flash_M25P64_EraseAll(void)
{
	Flash_M25P64_Set_Write(FLASH_M25P64_WRITE_EN);
	_delay(10);
	FLASH_M25P64_CS_0;
	Flash_Send_Byte(_FLASH_CMD_BE);
	FLASH_M25P64_CS_1;

	Flash_M25p64_Wait_For_Write_End();
	Flash_M25P64_Set_Write(FLASH_M25P64_WRITE_DIS);
}

